package com.fjwt.gz.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjwt.gz.core.cache.RedisUtil;
import com.fjwt.gz.core.constants.Constants;
import com.fjwt.gz.core.exception.BizException;
import com.fjwt.gz.db.bo.ActivityUserTimesBO;
import com.fjwt.gz.db.dto.FansUserDTO;
import com.fjwt.gz.db.entity.ActivityEntity;
import com.fjwt.gz.db.entity.ActivitySettingEntity;
import com.fjwt.gz.db.entity.ActivityWhitelistEntity;
import com.fjwt.gz.db.entity.BlacklistEntity;
import com.fjwt.gz.db.entity.BlacklistRuleEntity;
import com.fjwt.gz.db.entity.FansEntity;
import com.fjwt.gz.db.entity.ScoreRecordTotalEntity;
import com.fjwt.gz.service.mapper.ActivitySettingMapper;
import com.fjwt.gz.util.JsonUtils;
import com.fjwt.gz.util.PeriodUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.Time;
import java.time.LocalTime;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 营销活动配置表 服务实现类
 * </p>
 *
 * @author shiyonghao
 * @since 2025-04-09
 */
@Slf4j
@Service
public class ActivitySettingService extends ServiceImpl<ActivitySettingMapper, ActivitySettingEntity> {

    @Autowired
    private ActivitySettingMapper activitySettingMapper;
    @Autowired
    private ActivityWhitelistService activityWhitelistService;
    @Autowired
    private ActivityAppService activityAppService;
    @Autowired
    private ScoreRecordTotalService scoreRecordTotalService;
    @Autowired
    private BlacklistRuleService blacklistRuleService;
    @Autowired
    private BlacklistService blacklistService;


    /**
     * 参与活动校验ActivitySetting
     **/
    public JSONObject checkActivitySetting(FansEntity fansEntity, String appId, Long redisOutTime, ActivityEntity activityEntity) {
        JSONObject settingReqJosn = new JSONObject();
        log.info("参与活动校验ActivitySettingEntity进来的参数是：fansId:{},redisOutTime:{},activityEntity:{}", fansEntity.getFansId(), redisOutTime, JSONUtil.toJsonStr(activityEntity));
        ActivitySettingEntity activitySettingEntity = getActivitySettingEntity(activityEntity.getActivityId(), redisOutTime);
        log.info("查询出来的ActivitySettingEntity信息是：{}", JSONUtil.toJsonStr(activitySettingEntity));

        //是否关注公众号
        fansIsFllowOfficial(fansEntity, activitySettingEntity);

        //校验黑名单
        checkBlacklist(fansEntity, redisOutTime, activitySettingEntity, appId);
        //校验白名单
        checkWhites(fansEntity, redisOutTime, activityEntity, activitySettingEntity, settingReqJosn);

        String currentTimesKey = String.format("%s%s:%s%s", Constants.REDIS_ACTIVITY.FILENAME, activityEntity.getActivityId(), Constants.REDIS_ACTIVITY.USER_FILENAME, fansEntity.getFansId());//用户参会活动次数redis缓存key
        log.info("每人参与的总次数redisKey:{}", currentTimesKey);
        ActivityUserTimesBO activityUserTimesBO = RedisUtil.getObject(currentTimesKey, ActivityUserTimesBO.class);//用户参会活动次数redis缓存
        log.info("每人参与的总次数redisValue:{}", JSONUtil.toJsonStr(activityUserTimesBO));

        //判断每人参与的总次数
        activityUserTimesBO = checkPersonJoinTimes(activitySettingEntity, activityUserTimesBO);
        //判断周期性次数
        activityUserTimesBO = checkPeriodTypeTimes(activitySettingEntity, activityUserTimesBO);
        //特殊日期判断校验
        checkSpecialType(activitySettingEntity);
        //每天时间段限制判断
        checkeveryDayJoinTime(activitySettingEntity);
        //参与活动积分奖励
        //用户参与福分奖励redis缓存key
        String userJoinScoreKey = String.format("%s%s:%s%s", Constants.REDIS_ACTIVITY.FILENAME, activityEntity.getActivityId(), Constants.REDIS_ACTIVITY.USER_JOIN_SCORE, fansEntity.getFansId());
        Boolean isFirstJoin = joinActivityAddScore(activitySettingEntity, userJoinScoreKey, activityEntity.getAgentNo(), fansEntity, appId, activityEntity.getActivityName());
        settingReqJosn.put("currentTimesKey", currentTimesKey);
        settingReqJosn.put("activityUserTimesBO", activityUserTimesBO);
        settingReqJosn.put("userJoinScoreKey", userJoinScoreKey);
        settingReqJosn.put("userJoinScoreValue", isFirstJoin);
        return settingReqJosn;
    }

    /**
     * 更新Redis中用户参与次数
     */
    public void updateRedisParticipateNum(String currentTimesKey, ActivityUserTimesBO activityUserTimesBO, Long redisOutTime) {
        log.info("更新个人参与次数的Redis数据,redisKey:{},redisValue:{},redisOutTime:{},TimeUnit:{}", currentTimesKey, JSONUtil.toJsonStr(activityUserTimesBO), redisOutTime, "TimeUnit.MILLISECONDS");
        RedisUtil.set(currentTimesKey, activityUserTimesBO, redisOutTime, TimeUnit.MILLISECONDS);
    }

    /**
     * 用户是否关注公众号
     **/
    private void fansIsFllowOfficial(FansEntity fansEntity, ActivitySettingEntity activitySettingEntity) {
        if (activitySettingEntity.getIsFollowOfficial() == 1) {
            // 查询活动关联公众号用户信息
            FansUserDTO fansUser = activityAppService.getFansUerByActivityId(activitySettingEntity.getActivityId(), fansEntity.getFansId());
            if (ObjectUtils.isEmpty(fansUser) || 1 == fansUser.getIsFollow()) {
                throw new BizException("请先关注公众号");
            }
        }
    }

    /**
     * 特殊日期判断校验
     **/
    private static void checkSpecialType(ActivitySettingEntity activitySettingEntity) {
        final int specialType = activitySettingEntity.getSpecialType();
        if (specialType != 0) {
            final String specialContent = activitySettingEntity.getSpecialContent();
            Date date = DateUtil.date();
            String currentDay = specialType == 1 ? String.valueOf(DateUtil.dayOfWeek(date) - 1) : DateUtil.today();
            if (!specialContent.contains(currentDay)) {
                throw new BizException("对不起，当前日期不可参与活动");
            }
        }
    }

    /**
     * 判断周期性次数
     **/
    private static ActivityUserTimesBO checkPeriodTypeTimes(ActivitySettingEntity activitySettingEntity, ActivityUserTimesBO activityUserTimesBO) {
        if (activitySettingEntity.getPeriodType() > 0) {
            if (activityUserTimesBO != null) {
                int currentPeriodTimes = activityUserTimesBO.getCurrentPeriodTimes();
                int historyPeriod = activityUserTimesBO.getCurrentPeriod();
                final int periodTimes = activitySettingEntity.getPeriodTimes();
                int currentPeriod = PeriodUtil.getPeriod(activitySettingEntity.getPeriodType());
                if (currentPeriod == historyPeriod) {
                    if (currentPeriodTimes >= periodTimes) {
                        String type = activitySettingEntity.getPeriodType() == Constants.PERIOD.DAY ? "日" : activitySettingEntity.getPeriodType() == Constants.PERIOD.WEEK ? "周" : activitySettingEntity.getPeriodType() == Constants.PERIOD.MONTH ? "月" : "年";
                        throw new BizException(String.format("对不起，您每%s参与的次数已用完", type));
                    } else {
                        currentPeriodTimes++;
                        activityUserTimesBO.setCurrentPeriodTimes(currentPeriodTimes);
                    }
                } else {
                    activityUserTimesBO.setCurrentPeriodTimes(1);
                    activityUserTimesBO.setCurrentPeriod(currentPeriod);
                }
            } else {
                activityUserTimesBO = new ActivityUserTimesBO();
                activityUserTimesBO.setCurrentPeriodTimes(1);
                activityUserTimesBO.setCurrentPeriod(PeriodUtil.getPeriod(activitySettingEntity.getPeriodType()));
            }
        }
        return activityUserTimesBO;
    }

    /**
     * 参与活动奖励积分
     **/
    private Boolean joinActivityAddScore(ActivitySettingEntity activitySettingEntity, String userJoinScoreKey, String agentNo, FansEntity fansEntity, String appId, String actvityName) {
        //参与活动积分奖励
        int firstJoinScore = activitySettingEntity.getFirstJoinScore();
        int everyJoinScore = activitySettingEntity.getEveryJoinScore();
        int overDays = activitySettingEntity.getOverDays();
        Date overTime = activitySettingEntity.getOverTime();
        int overType = activitySettingEntity.getOverType();
        ScoreRecordTotalEntity scoreRecordTotalEntity = new ScoreRecordTotalEntity();
        //组装参数
        scoreRecordTotalEntity.setFansId(fansEntity.getFansId());
        scoreRecordTotalEntity.setAppId(appId);
        scoreRecordTotalEntity.setInfoId(activitySettingEntity.getActivityId());
        scoreRecordTotalEntity.setInfoType(Constants.SCORE.ACTIVITY);
        scoreRecordTotalEntity.setFlag(Constants.SCORE_FLAG.ADD);
        scoreRecordTotalEntity.setOverTime(overTime);
        scoreRecordTotalEntity.setActivityId(activitySettingEntity.getActivityId());

        Boolean isFirstJoin = RedisUtil.getObject(userJoinScoreKey, Boolean.class);

        // 有首次参与奖励积分
        if (firstJoinScore > 0) {
            // 用户是首次参与
            if (isFirstJoin == null || isFirstJoin) {
                scoreRecordTotalEntity.setName(String.format("首次参加%s奖励福分", actvityName));
                scoreRecordTotalEntity.setScore(activitySettingEntity.getFirstJoinScore());
                isFirstJoin = false;
                scoreRecordTotalService.addScoreRecordTotal(agentNo, scoreRecordTotalEntity, overDays, overType, overTime);
            }else if (everyJoinScore > 0) {
                // 用户不是首次并且有每次参与奖励
                scoreRecordTotalEntity.setName(String.format("每次参加%s奖励福分", actvityName));
                scoreRecordTotalEntity.setScore(activitySettingEntity.getEveryJoinScore());
                scoreRecordTotalService.addScoreRecordTotal(agentNo, scoreRecordTotalEntity, overDays, overType, overTime);
            }
        }else if (everyJoinScore > 0){
            // 没有首次参与奖励只有每次参与奖励
            scoreRecordTotalEntity.setName(String.format("每次参加%s奖励福分", actvityName));
            scoreRecordTotalEntity.setScore(activitySettingEntity.getEveryJoinScore());
            scoreRecordTotalService.addScoreRecordTotal(agentNo, scoreRecordTotalEntity, overDays, overType, overTime);
        }
        return isFirstJoin;
    }

    /**
     * 校验用户参与时间段
     **/
    private void checkeveryDayJoinTime(ActivitySettingEntity activitySettingEntity) {
        final int timeType = activitySettingEntity.getTimeType();
        if (timeType != 0) {
            Time startTime = activitySettingEntity.getTimeStart();
            Time endTime = activitySettingEntity.getTimeEnd();
            LocalTime currentTime = LocalTime.now();
            if (currentTime.isBefore(startTime.toLocalTime()) || currentTime.isAfter(endTime.toLocalTime())) {
                throw new BizException("对不起，当前时间段不可参与活动");
            }
        }
    }

    /**
     * 校验用户每人参与总次数
     **/
    private ActivityUserTimesBO checkPersonJoinTimes(ActivitySettingEntity activitySettingEntity, ActivityUserTimesBO activityUserTimesBO) {
        final int onlyOneTimes = activitySettingEntity.getOnlyOneTimes();
        if (onlyOneTimes > 0) {
            if (activityUserTimesBO != null) {
                int totalJoinTimes = activityUserTimesBO.getTotalJoinTimes();
                if (totalJoinTimes >= onlyOneTimes) {
                    throw new BizException("对不起，您参与的总次数已用完");
                } else {
                    totalJoinTimes++;
                    activityUserTimesBO.setTotalJoinTimes(totalJoinTimes);
                }
            } else {
                activityUserTimesBO = new ActivityUserTimesBO();
                activityUserTimesBO.setTotalJoinTimes(1);
            }
        }
        return activityUserTimesBO;
    }

    /**
     * 校验用户白名单  0 --没有限制白名单  1--在白名单里面  2--不在白名单里面  TODO  注意：这个是返回上一级调用的，根据对应的类型进行白名单的处理
     **/
    private void checkWhites(FansEntity fansEntity, Long redisOutTime, ActivityEntity activityEntity, ActivitySettingEntity activitySettingEntity, JSONObject settingReqJosn) {
        if (activitySettingEntity.getHasWhitelist() != 0) {
            //校验白名单
            Map<String, ActivityWhitelistEntity> activityWhiteMap = activityWhitelistService.getActivityWhiteMap(activityEntity.getActivityId(), redisOutTime);
            if (null != activityWhiteMap.get(fansEntity.getPhone())) {
                settingReqJosn.put("isWhite", 1);
            } else {
                settingReqJosn.put("isWhite", 2);
            }
        } else {
            settingReqJosn.put("isWhite", 0);
        }
    }

    /**
     * 校验黑名单
     **/
    private void checkBlacks(FansEntity fansEntity, Long redisOutTime, ActivitySettingEntity activitySettingEntity) {
        //校验黑白名单
        if (activitySettingEntity.getHasBlacklist() != 0) {
            //根据活动id查询活动黑名单对应的多条黑名单规则
            List<BlacklistRuleEntity> activityBlacRulesList = blacklistRuleService.getActivityBlacRulesList(activitySettingEntity.getActivityId(), redisOutTime);
            //循环黑名单规则，查询所有的黑名单列表
            for (BlacklistRuleEntity blackListRule : activityBlacRulesList) {
                Map<String, BlacklistEntity> blackListMap = blacklistService.getBlackListByRuleId(blackListRule, redisOutTime);
                BlacklistEntity blackListEntity = blackListMap.get(fansEntity.getPhone());
                if (ObjectUtils.isNotEmpty(blackListEntity)) {
                    log.info("用户在黑名单内，用户信息是：{}", JsonUtils.toJson(blackListEntity));
                    throw new BizException("抱歉，您不符合参与活动的规则！");
                }
            }
        }
    }


    /**
     * 校验用户是否在黑名单中
     *
     * @param fansEntity            用户信息
     * @param redisOutTime          redis过期时间
     * @param activitySettingEntity 活动配置信息
     */
    private void checkBlacklist(FansEntity fansEntity, Long redisOutTime, ActivitySettingEntity activitySettingEntity, String appId) {
        // 获取活动ID
        Long activityId = activitySettingEntity.getActivityId();
        // 查询黑名单规则列表
        List<BlacklistRuleEntity> blacklistRuleEntities = blacklistRuleService.getActivityBlacRulesList(activityId, redisOutTime);
        log.info("活动对应黑名单规则列表,{}", blacklistRuleEntities);
        //公共校验
        blacklistRuleService.commonBlacklistRuleValid(blacklistRuleEntities, fansEntity, activityId, 0, redisOutTime, appId);
    }


    /**
     * 获取活动配置信息
     **/
    public ActivitySettingEntity getActivitySettingEntity(Long activityId, Long redisOutTime) {
        String activitySettingKey = String.format("%s%s:%s", Constants.REDIS_ACTIVITY.FILENAME, activityId, Constants.REDIS_ACTIVITY.SETTING);
        log.info("用户参与限制条件redisKey:{}", activitySettingKey);
        ActivitySettingEntity activitySettingEntity = RedisUtil.getObject(activitySettingKey, ActivitySettingEntity.class);
        if (activitySettingEntity == null) {
            LambdaQueryWrapper<ActivitySettingEntity> activitySettingWapper = new LambdaQueryWrapper<>();
            activitySettingWapper.eq(ActivitySettingEntity::getActivityId, activityId);
            activitySettingEntity = activitySettingMapper.selectOne(activitySettingWapper);
            if (activitySettingEntity != null) {
                RedisUtil.set(activitySettingKey, activitySettingEntity, redisOutTime, TimeUnit.MILLISECONDS);
                log.info("用户参与限制条件，从数据库加载到redis缓存中，，redisKey:{},redisValue:{},redisOutTime:{},TimeUnit:{}", activitySettingKey, JSONUtil.toJsonStr(activitySettingEntity), redisOutTime, "TimeUnit.MILLISECONDS");
            }
        } else {
            log.info("用户参与限制条件，redis缓存，redisKey:{},redisValue:{},redisOutTime:{},TimeUnit:{}", activitySettingKey, JSONUtil.toJsonStr(activitySettingEntity), redisOutTime, "TimeUnit.MILLISECONDS");
        }
        return activitySettingEntity;
    }
}
